-- SaintTacticsM
-- Created by dengc Sep/1/2016
-- 圣者之塔BOSS策略

module("SaintTacticsM", package.seeall);

-- 倒计时开始的回合
local COUNT_DOWN_START_ROUND = 3;

-- 初始时激活的石柱类型
local INIT_ACTIVE_STONE_TYPE = STONE_TYPE_DARK;

-- 初始化
function init()
    EventMgr.removeAll("SaintTacticsM");

    -- 关注回合数变化
    CombatM.registerStartRoundCB("saint_boss_start_round", whenCombatRound);

    -- 关注玩家离开地牢的事件
    EventMgr.register("SaintTacticsM", event.LEAVE_DUNGEON, function()
        resetCounter();
    end);

    -- 关注层数回退（大地之门等技能）的事件
    EventMgr.register("SaintTacticsM", event.BACK_FLOOR, function()
        resetCounter();
    end);

    -- 关注地牢准备完毕事件
    EventMgr.register("SaintTacticsM", event.DUNGEON_PREPARE_OVER, function()
        resetCounter();
    end);
end

-- 回合数变化
whenCombatRound = function()
    -- 只处理在Boss层的情况
    if not DungeonBossM.isInBossLayer() then return; end

    -- 更新计数器
    updateCounter();
end

-- 迷宫层数变化
resetCounter = function()
    -- 把上次石柱的负面状态删除
    CombatStatusM.clearStatusByRule(ME.user, "stone_prop");

    -- 删除记录
    ME.user.dbase:deleteTemp("counter");

    -- 刷新石柱数据
    if DungeonBossM.isInBossLayer() then 
        initStoneData();

        -- 重置计数器
        initCounter();
    end
end

-- 更新计数器
updateCounter = function()
    local counter = ME.user.dbase:queryTemp("counter");
    if not counter then
        return;
    end

    if counter.status == COUNTER_STATUS_SLEEP then
        return;
    end

    -- 检查玩家是否使用了时间停止
    local prop = PropM.combine(ME.user, "stop_action", 1);
    if PropM.apply(prop, 1) > 0 then
        return;
    end

    -- 计数器自减一
    if counter.count > 1 then
        counter.count = counter.count - 1;
    -- 尝试更新策略
    else
        counter.count = COUNT_DOWN_START_ROUND;
        counter.status = COUNTER_STATUS_SLEEP;

        local stoneList = findStoneList();

        -- 获取将要改变的石柱
        local stoneType = counter.appendStone;
        for _, stone in pairs(stoneList) do
            if stone.stoneType == stoneType and stone.state ~= GRID_STATE_DISABLE then
                -- 更新石柱状态
                changeStoneStatus(stone.pos, stone.stone_id);
            end
        end
    end
end

-- 找到石柱
function findStoneList()
    local stoneList = {};

    local grids = DungeonM.getCurrentDungeon() or {};
    for _, grid in pairs(grids) do
        if grid.type == GRID_TYPE_BOSS_STONE then
            local pos = grid.pos;
            stoneList[pos] = grid;
        end
    end

    return stoneList;
end

-- 倒计时生成器
function initCounter()
    if not DungeonBossM.isInBossLayer() then
        return;
    end

    local counter = {};

    -- 属性
    counter.count = COUNT_DOWN_START_ROUND;
    counter.status = COUNTER_STATUS_SLEEP;
    counter.appendStone = STONE_TYPE_LIGHT;
    counter.bossStatus = BOSS_STATUS_DARK;

    -- 记录在玩家身上
    ME.user.dbase:setTemp("counter", counter);
end

-- 初始化石柱数据
function initStoneData()
    local stoneList = {};
    local grids = DungeonM.getCurrentDungeon() or {};
    for _, grid in pairs(grids) do
        -- 格子的类型是石柱
        if grid.type == GRID_TYPE_BOSS_STONE and grid.stone_id then
            -- 记录石柱的类型
            local stoneType = MagicStoneM.query(grid.stone_id, "type");
            grid.stoneType = stoneType;

            -- 设置激活状态
            local stoneStatus = STONE_STATE_CLOSED;
            grid.stoneStatus = stoneStatus;

            -- 记录
            stoneList[grid.pos] = grid;

            -- 尝试激活石柱
            if grid.stoneType == INIT_ACTIVE_STONE_TYPE then
                -- 标记有特效需要播放
                ME.user.dbase:setTemp("boss_stone_effect", { 
                    ["pos"] = grid.pos, 
                    ["status"] = STONE_STATE_OPENED,
                    ["id"] = grid.stone_id, 
                });

                -- 改变石柱状态
                changeStoneStatus(grid.pos, grid.stone_id, true);
            end
        end
    end
end

-- 关闭石柱
function closeStone(pos, stoneId)
    local counter = ME.user.dbase:queryTemp("counter");
    if not counter then
        return;
    end

    local stoneType = MagicStoneM.query(stoneId, "type");
    if stoneType == STONE_TYPE_DARK then
        -- 关闭暗之石柱
        counter.appendStone = STONE_TYPE_LIGHT;
        counter.bossStatus = BOSS_STATUS_LIGHT;
    else
        -- 关闭光之石柱
        counter.appendStone = STONE_TYPE_DARK;
        counter.bossStatus = BOSS_STATUS_DARK;
    end

    -- 改变沙漏显示
    changeCdNode(pos);

    -- 改变boss形态
    changeBossStatus();

    -- 改变石柱形态
    changeStoneStatus(pos, stoneId);
end

-- 改变沙漏的状态
function changeCdNode(pos)
    local counter = ME.user.dbase:queryTemp("counter");
    if not counter then
        return;
    end

    local stoneList = findStoneList();

    counter.status = COUNTER_STATUS_ACTIVE;
    counter.count = COUNT_DOWN_START_ROUND;

    local appendStoneType = counter.appendStone;
    for _, stone in pairs(stoneList) do
        if stone.stoneType == appendStoneType then
            EventMgr.fire(event.UPDATE_STONE_CD, { ["pos"] = stone.pos, });
        end
    end
end

-- 改变boss的状态
function changeBossStatus()
    local pos = DungeonBossM.getBossPos();

    -- 查询变身配置
    local boss = DungeonM.getGridByPos(pos).monster;
    local props = PropM.fetchProps(boss, "close_to_transform");
    if #props == 0 then
        return;
    end

    -- 获取释放的技能
    local prop = props[1];
    local skillId = tonumber(prop[2]);
    if not skillId then
        trace("SaintTacticsM", "未配置转变后的id！");
        return;
    end

    -- 获取转变后的id
    local toClassId = tonumber(prop[3]);
    if not toClassId then
        trace("SaintTacticsM", "未配置转变后的id！");
        return;
    end

    -- 变身
    SkillM.apply(boss, boss, skillId, CombatM.getRound(), { ["to_class_id"] = toClassId, });
end

-- 改变石柱的状态
function changeStoneStatus(pos, stoneId, noEffect)
    local stoneList = findStoneList();

    noEffect = noEffect or false;

    -- 获取不到
    local stone = stoneList[pos];
    if not stone then
        return;
    end

    -- 切换石柱状态
    stone.stoneStatus = (stone.stoneStatus == STONE_STATE_OPENED) and STONE_STATE_CLOSED or STONE_STATE_OPENED;

    -- 根据状态清除或赋予DEBUF状态
    if stone.stoneStatus == STONE_STATE_OPENED then
        applyStoneBuf(stoneId);
    else
        -- 清除状态
        clearStoneBuf();

        -- 消耗
        doCost(pos);
    end

    -- 抛出切换状态事件
    if not noEffect then
        EventMgr.fire(event.UPDATE_STONE_STATUS, { ["pos"] = pos, ["status"] = stone.stoneStatus, ["id"] = stoneId, });
    end
end

-- 赋予debuf状态
function applyStoneBuf(stoneId)
    local stoneStatus = MagicStoneM.query(stoneId, "negative");
    if stoneStatus then
        local statusList = stoneStatus["status"];
        for _, status in pairs(statusList) do
            local alias = status["status"];
            local condition = table.deepcopy(status);

            -- 诅咒结界受诅咒免疫影响
            if alias == "dark_stone" then
                local arr = PropM.combine(ME.user, "immunity", "curse");
                if PropM.apply(arr, 1) == 0 then
                    CombatStatusM.applyStatus(ME.user, alias, condition);
                end
            else
                CombatStatusM.applyStatus(ME.user, alias, condition);
            end
        end
    end
end

-- 清除debuf状态
function clearStoneBuf()
    CombatStatusM.clearStatusByRule(ME.user, "stone_prop");
end

-- 获取计数器的值
function getCdCount(pos)
    local counter = ME.user.dbase:queryTemp("counter");
    if not counter then
        return -1;
    end

    -- 计数器处于休眠状态
    if counter.status == COUNTER_STATUS_SLEEP then
        return -1;
    end

    local stoneList = findStoneList();

    -- 获取不到石柱
    local stone = stoneList[pos];
    if not stone then
        return -1;
    end

    -- 不是计时器此时所挂载的石柱
    if counter.appendStone ~= stone.stoneType then
        return -1;
    end

    return counter.count;
end

-- 获取石柱的状态
function getStoneStatus(pos)
    local stoneStatus = STONE_STATE_COVER;

    local stoneList = findStoneList();

    local stone = stoneList[pos];
    if stone then
        stoneStatus = stone.stoneStatus;
    end

    return stoneStatus;
end

-- 检查是否能关闭石柱
function checkClosed(pos)
    local stoneList = findStoneList();

    local stone = stoneList[pos];
    local id = stone.stone_id
    local cost = MagicStoneM.query(id, "closed_cost") or {};

    local ok = true;
    for key, amount in pairs(cost) do
        if type(key) == "string" then
            -- 属性
            ok = ME.user.dbase:query(key, 0) >= amount;
        elseif type(key) == "number" then
            -- 物品
            ok = ItemM.getAmount(ME.user, key) >= amount;
        else
            -- 暂无其他消耗
            ok = false;
        end

        if not ok then
            trace("MagicStoneM", "%s不足，不能关闭石柱。", tostring(key));
            return ok;
        end
    end

    return ok;
end

-- 扣除消耗
function doCost(pos)
    local stoneList = findStoneList();

    local stone = stoneList[pos];
    local id = stone.stone_id;
    local pos = stone.pos;

    -- 消耗
    local cost = MagicStoneM.query(id, "closed_cost") or {};
    for key, amount in pairs(cost) do
        if type(key) == "number" then
            ItemM.costAmount(ME.user, key, amount);
        elseif type(key) == "string" then
            ME.user:costAttrib(key, amount);
        end
    end

    DungeonLogM.addLog("解除石柱。");

    return true;
end
